home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1994…tember: Reference Library / Dev.CD Sep 94.toast / Periodicals / develop / develop Issue 9 / develop 9 code / Color on 1-Bit Devices / Halftone.c < prev   
Encoding:
C/C++ Source or Header  |  1992-01-06  |  8.0 KB  |  308 lines  |  [TEXT/KAHL]

  1. /*******************************
  2.     Halftoning Sample Code:
  3.  
  4.     D. Lipton
  5.     
  6. ********************************/
  7.  
  8. #ifndef THINK_C
  9.     #include <QuickDraw.h>
  10.     #include <QDOffscreen.h>
  11.     #include <Events.h>
  12.     #include <FixMath.h>
  13. #endif
  14.  
  15.  
  16. /*****************
  17.     Define target resolution value:
  18.     Note, if less than 72, source scaling
  19.     code does not work.  It assumes target
  20.     resolution is always >= 72 so pointer 
  21.     arithmetic in source image doesn't need
  22.     to do a multiply every time.  This could
  23.     be fixed at the expense of performance
  24. ******************/
  25. #define RES 72
  26.  
  27. /*************
  28.     Routine returns luminance for a pixel.
  29.     
  30.     pPixel points to the pixel in the PixMap.
  31.     pMap is the Pixmaps PixMapPtr.
  32.     
  33.       Non optimal for 8 bit.
  34.       Should cache luminances for CLUT and read them back
  35.       rather than calculating for every pixel.
  36.           Left as an exercise for the reader.
  37.     
  38. **************/
  39.  
  40. long LUMVAL(Ptr pPixel, PixMapPtr pMap)
  41.     {
  42.         long                red, green, blue;
  43.         
  44.         if (pMap->pixelSize == 32) {
  45.         
  46.             red = (long)(unsigned char)*(++pPixel);                /* Skip alpha, get red */
  47.             green = (long)(unsigned char)*(++pPixel);            /* Get green */
  48.             blue = (long)(unsigned char)*(++pPixel);            /* Get blue */
  49.             
  50.             return( (30 * red + 59 * green + 11 * blue)/100);
  51.         
  52.         } else if (pMap->pixelSize == 8) {
  53.         
  54.             RGBColor*                theColor;
  55.             theColor = &((*(pMap->pmTable))->ctTable[ (unsigned char)*pPixel  ].rgb);
  56.             
  57.             return( (30 * (theColor->red >> 8) + 59 * (theColor->green >> 8) + 11 * (theColor->blue >> 8))/100);
  58.         
  59.         } /* end if */
  60.     
  61.     } /* LUMVAL */
  62.  
  63.  
  64.  
  65.  
  66.  
  67. /*******************************
  68.     Routine:  HalftonePixMap:
  69.     
  70.     Routine takes a pixmap and halftones it
  71.     into a 300dpi 1 bit gworld.
  72.     
  73.     The halftoned image is returned in a picture handle.
  74.     
  75. ********************************/
  76. PicHandle HalftonePixMap(PixMapHandle hSource, Boolean qdPixMap,
  77.     short    Resolution)
  78.     {
  79.         short                                width300, height300;
  80.         /*  300-dpi width and height. */
  81.         Fixed                                scale;
  82.         Rect                                bounds300;
  83.         QDErr                                status;
  84.         GWorldPtr                        theGworld;
  85.         PixMapHandle                    offScreen;
  86.         Fixed                                sourceX, sourceY;
  87.         short                                lastX, lastY;
  88.         short                                destX, destY;
  89.         Ptr                                pRaster, pPixel, pDestRaster;
  90.         long                                *nextDestLong;
  91.         long                                luminance;
  92.         register unsigned long        mask, destLong;
  93.         PicHandle                        aPic;
  94.         PixMap                            *pSource;
  95.         long        matrix[8][8] = { 7,  111, 183, 239, 231, 191, 71, 15, 
  96.                                             87, 47, 135, 175, 199, 159, 55, 127, 
  97.                                             215, 143, 39, 79, 119, 63, 151, 207, 
  98.                                             247, 223, 103, 31, 23, 95, 167, 255 ,
  99.                                             231, 191, 71, 15, 7, 111, 183, 239 ,
  100.                                             199, 159, 55, 127, 87, 47, 135, 175, 
  101.                                             119, 63, 151, 207, 215, 143, 39, 79, 
  102.                                             23, 95, 167, 255, 247, 223, 103, 31
  103.                                             }; 
  104.  
  105.         long                                *pMatrix, *pMatrixRow;
  106.         long                                M = 8;
  107.         long                                N = 8;
  108.         long                                I, J;
  109.         /* Matrix coordinates. */
  110.         
  111.         if(Resolution == 0)
  112.             Resolution = 72;
  113.  
  114.         if(Resolution < 72)
  115.             return(0);
  116.  
  117.         HLock(hSource);
  118.         if(qdPixMap)
  119.             LockPixels(hSource);
  120.             
  121.         pSource = *hSource;
  122.         
  123.         scale = FixRatio(Resolution, 72);
  124.     
  125.         /* Compute width and height at new resolution. */
  126.     
  127.         width300 = FixMul(scale, (long)(pSource->bounds.right - 
  128.             pSource->bounds.left) << 16) >> 16;
  129.         height300 = FixMul(scale, (long)(pSource->bounds.bottom -
  130.             pSource->bounds.top) << 16) >> 16;
  131.     
  132.     
  133.         bounds300.top = pSource->bounds.top;
  134.         bounds300.bottom = bounds300.top + height300;
  135.         bounds300.left = pSource->bounds.left;
  136.         bounds300.right = bounds300.left + width300;
  137.     
  138.     
  139.         /* Allocate a 1-bit GWorld to draw into. */
  140.         
  141.         status = NewGWorld(&theGworld, 1, &bounds300, nil, nil, 0);
  142.         if (status)
  143.             return nil;
  144.             
  145.             
  146.         offScreen = GetGWorldPixMap(theGworld);  /* 7.0 only */
  147.         LockPixels(offScreen);
  148.         
  149.         /* Compute scale for walking source pixels. */
  150.         scale = FixRatio(72, Resolution);
  151.         
  152.         /* Source X, Y will walk source image in fixed-point numbers.
  153.             Integer part will be saved to see when we've crossed into
  154.             a new pixel boundary for updating pointers and luminance
  155.             value. */
  156.         
  157.         sourceY = pSource->bounds.top << 16;
  158.         lastY = sourceY >> 16;
  159.         
  160.         /* Initialize raster pointers. */
  161.         if( qdPixMap )
  162.             pRaster = GetPixBaseAddr(hSource);
  163.         else
  164.             pRaster = pSource->baseAddr;
  165.             
  166.         pDestRaster = GetPixBaseAddr(offScreen);
  167.         
  168.         I = 0;                                /* Y index into dither matrix. */
  169.         pMatrixRow = &(matrix[0][0]);    /* Point to next row of matrix. */
  170.         
  171.         for (destY = 0; destY < height300; ++destY) {
  172.         
  173.             pPixel = pRaster;
  174.             luminance = LUMVAL(pPixel, pSource);
  175.             mask = 0x80000000;
  176.             destLong = 0;
  177.             nextDestLong = (long*)pDestRaster;
  178.  
  179.             sourceX = pSource->bounds.left << 16;
  180.             lastX = sourceX >> 16;
  181.  
  182.             J = 0;                            /* X index into dither matrix. */
  183.             pMatrix = pMatrixRow;        /* Point into current row of
  184.                                                     dither matrix. */
  185.  
  186.             for (destX = 0; destX < width300; ++destX) {
  187.  
  188.                 /* If the luminance for this pixel is less than matrix
  189.                     value, turn on the pixel. */
  190.                 
  191.                 if (luminance < *pMatrix)
  192.                     destLong |= mask;
  193.                     
  194.                 /* Adjust masks and longs for next device pixel.
  195.                     Pixels are set in a long-word register. When all
  196.                     32 bits in the register have been set, the register
  197.                     is layed into the pixMap. */
  198.                 
  199.                 mask >>= 1;
  200.                 if (mask == 0) {            /* We've done 32 pixels, lay in
  201.                                                     the long word into the
  202.                                                     offscreen. */
  203.                     mask = 0x80000000;    /* Reset the mask. */
  204.                     *(nextDestLong++) = destLong;
  205.                     destLong = 0;
  206.                 } /* End if */
  207.  
  208.  
  209.                 /* Update pointer into dither matrix:
  210.                     Instead of using matrix[X % M, Y % N],
  211.                     we use a pointer and counters. Mod function
  212.                     combined with an array index calculation would
  213.                     be more time-consuming. */
  214.                 
  215.                 ++pMatrix;                    /* Next element in row. */
  216.                 if (++J >= N) {            /* Get J+1 mod N, faster than
  217.                                                     doing real mod every pixel. */
  218.                 
  219.                     J = 0;
  220.                     pMatrix = pMatrixRow;    /* Start at beginning of matrix
  221.                                                         row again. */
  222.                 
  223.                 } /* End if */
  224.                                     
  225.                 
  226.                 sourceX += scale;            /* Add fixed scale increment to
  227.                                                     source X value. */
  228.                 
  229.                 /* Check to see if we crossed into next source pixel.
  230.                     Note: Getting integer portion can be done faster than 
  231.                     a shift; this is left as an exercise for the reader. */
  232.                 if ((sourceX >> 16) > lastX) {
  233.                 
  234.                     lastX = sourceX >> 16;
  235.                     /* Get new integer portion of X coordinate. */
  236.                     if (pSource->pixelSize == 8)
  237.                     /* Point to next 8-bit pixel. */
  238.                         ++pPixel;
  239.                     else if (pSource->pixelSize == 32)
  240.                     /* Point to next 32-bit pixel. */
  241.                         pPixel += 4;
  242.                     
  243.                     luminance = LUMVAL(pPixel, pSource);
  244.                     /* Get luminance for next pixel. */
  245.                 
  246.                 } /* End if */
  247.                         
  248.             
  249.             } /* End for */
  250.         
  251.             /* Make sure the last long-word was laid into the target
  252.                 image. If 1 in the mask is not all the way left, it means
  253.                 there are pixels in the next long, but not enough to force
  254.                 the write within the raster loop, so lay it into the
  255.                 block. */
  256.             if (mask != 0x80000000)
  257.                 *nextDestLong = destLong;
  258.  
  259.             pDestRaster += ((*offScreen)->rowBytes & 0x3fff);
  260.             /* Get into next destination raster. */
  261.             
  262.             sourceY += scale;
  263.             /* Add fixed scale increment to source Y value. */
  264.             /* Checked to see if we crossed into next source raster. */
  265.             if ( (sourceY >> 16) > lastY ) {
  266.             
  267.                 lastY = sourceY >> 16;
  268.                 /* Get integer portion of Y coordinate. */
  269.                 pRaster += (pSource->rowBytes & 0x3fff);
  270.                 /* Get next source raster. */
  271.             
  272.             } /* End if */
  273.  
  274.             /* Update pointer into dither matrix. */
  275.             
  276.             pMatrixRow += M;        /* Point to next row of matrix. */
  277.             if (++I >= M) {
  278.             /* Get I+1 mod M, faster than doing real mod every raster. */
  279.             
  280.                 I = 0;
  281.                 pMatrixRow = &(matrix[0][0]);
  282.                 /* Point to next row of matrix. */
  283.             
  284.             } /* End if */
  285.  
  286.  
  287.         } /* End for */
  288.  
  289.  
  290.         /* Create the picture to return and dispose of the offscreen. */
  291.         
  292.         aPic = OpenPicture(&bounds300);
  293.         HLock((Handle)offScreen);
  294.         CopyBits((BitMap*)*offScreen, &thePort->portBits, &bounds300,
  295.             &bounds300, 0, 0L);
  296.         ClosePicture();
  297.         
  298.         DisposeGWorld(theGworld);
  299.         
  300.         HUnlock(hSource);
  301.         if(qdPixMap)
  302.             UnlockPixels(hSource);
  303.  
  304.         return(aPic);    
  305.     
  306.     } /* HalftonePixMap */
  307.  
  308.